﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Linq;

namespace StarESHelper
{
    public class EsModel
    {
        public class ESSearchResponseDto
        {
            public int page { get; set; } = 1;


            public int psize { get; set; } = 20;


            public int total { get; set; } = 0;


            public int totalPage => (int)Math.Ceiling((double)total / (double)psize);

            public string essql { get; set; }

            public long timecost { get; set; }

            public IEnumerable<JToken> rows { get; set; }

            public bool success { get; set; }

            public JToken error { get; set; }

            public IEnumerable<T> ToList<T>()
            {
                if (rows != null)
                {
                    return rows.Select((JToken t) => t.ToObject<T>());
                }

                return new List<T>();
            }
        }

        public class ESSearchRequestDto
        {
            /// <summary>
            /// 查询类型
            /// </summary>
            public string querytype = "query_string";
            /// <summary>
            /// should or must
            /// </summary>
            public bool termwhiteshould = false;
            /// <summary>
            /// 当前页
            /// </summary>
            private int _page = 1;
            /// <summary>
            /// 最大页码
            /// </summary>
            private int _maxpsize = 100;
            /// <summary>
            /// 页面容量
            /// </summary>
            private int _psize = 20;
            /// <summary>
            /// 搜索关键词
            /// </summary>
            public string keyword { get; set; } = string.Empty;

            /// <summary>
            /// 搜索字段
            /// </summary>
            public List<string> searchFields { get; set; } = new List<string>();
            /// <summary>
            /// 其他条件
            /// </summary>
            public Dictionary<string, string> boolmustObjects { get; set; } = new Dictionary<string, string>();

            /// <summary>
            /// 输出字段
            /// </summary>
            public List<string> outputFields { get; set; } = new List<string>();

            /// <summary>
            /// 参与得分字段
            /// </summary>
            public List<string> scoreFields { get; set; } = new List<string>();

            /// <summary>
            /// 得分步长
            /// </summary>
            public int scoreStep { get; set; } = 10;

            /// <summary>
            /// 当前页面
            /// </summary>
            public int page
            {
                get
                {
                    if (_page > maxPage)
                    {
                        return maxPage;
                    }

                    return _page;
                }
                set
                {
                    _page = value;
                }
            }
            /// <summary>
            /// 页面数量
            /// </summary>
            public int psize
            {
                get
                {
                    if (_psize > _maxpsize)
                    {
                        return _maxpsize;
                    }

                    return _psize;
                }
                set
                {
                    _psize = value;
                }
            }

            public int maxPage { get; set; } = 10;

        }
        /// <summary>
        /// 结果
        /// </summary>
        public class ApiResult
        {
            /// <summary>
            /// 是否查询成功
            /// </summary>
            public bool Success { get; set; }
            /// <summary>
            /// 查询错误信息
            /// </summary>
            public string ErrorMessage { get; set; } = string.Empty;

            /// <summary>
            /// 异常信息
            /// </summary>
            public Exception ErrorException { get; set; }
            /// <summary>
            /// 查询返回内容
            /// </summary>
            public string Content { get; set; } = string.Empty;

            /// <summary>
            /// 结果
            /// </summary>
            public ApiResultData Data { get; set; }
            /// <summary>
            /// 数据转换信息
            /// </summary>
            public string ConvertDataMessage { get; set; } = string.Empty;

            /// <summary>
            /// ES查询语句
            /// </summary>
            public string EsSQL { get; set; } = string.Empty;

            /// <summary>
            /// 请求数据
            /// </summary>
            public ESSearchRequestDto reqdto { get; set; }
            /// <summary>
            /// 查询返回数据
            /// </summary>
            /// <returns></returns>
            public ESSearchResponseDto ESSearchResponse()
            {
                ESSearchResponseDto essearchresponsedto = new ESSearchResponseDto();
                essearchresponsedto.success = false;
                int num = 0;
                if (reqdto != null)
                {
                    num = reqdto.maxPage;
                    essearchresponsedto.page = reqdto.page;
                    essearchresponsedto.psize = essearchresponsedto.psize;
                }

                if (!string.IsNullOrWhiteSpace(Content))
                {
                    JObject jObject = JObject.Parse(Content);
                    if (jObject["hits"] != null)
                    {
                        essearchresponsedto.success = true;
                        essearchresponsedto.timecost = long.Parse(jObject.SelectToken("took")?.ToString() ?? "");
                        essearchresponsedto.total = int.Parse(jObject.SelectToken("hits.total.value")?.ToString() ?? "");
                        if (num * essearchresponsedto.psize < essearchresponsedto.total)
                        {
                            essearchresponsedto.total = num * essearchresponsedto.psize;
                        }

                        essearchresponsedto.rows = ((JArray)jObject["hits"]["hits"]).Select((JToken a) => a["_source"]);
                    }

                    if (jObject["error"] != null)
                    {
                        essearchresponsedto.error = jObject["error"];
                    }
                }

                return essearchresponsedto;
            }
        }
        /// <summary>
        /// 查询结果数据
        /// </summary>
        public class ApiResultData
        {
            /// <summary>
            /// 结果代码
            /// </summary>
            public int result { get; set; }
            /// <summary>
            /// 结果信息
            /// </summary>
            public string message { get; set; } = string.Empty;

            /// <summary>
            /// 数据
            /// </summary>
            public JToken data { get; set; }
        }
        /// <summary>
        /// 请求返回数据
        /// </summary>
        public class RequestDto
        {
            /// <summary>
            /// 签名
            /// </summary>
            public string sign { get; set; } = string.Empty;

            /// <summary>
            /// 数据
            /// </summary>
            public string data { get; set; } = string.Empty;

            /// <summary>
            /// 请求耗时
            /// </summary>
            public long timestamp { get; set; }
        }

        private class RestSharpVerb
        {
            public string url { get; set; }

            public Method method { get; set; } = Method.Post;

            public string contenttype { get; set; } = "application/json";


            public int Timeout { get; set; } = -1;


            public Dictionary<string, string> headers { get; set; }

            public Dictionary<string, string> parameters { get; set; }

            public string body { get; set; } = string.Empty;


            public bool ConvertApiResultData { get; set; } = true;

        }

        public class RequestOption
        {
            public bool ConvertApiResultData = true;

            public bool withsign { get; set; }

            public string appsecret { get; set; } = string.Empty;


            public string contenttype { get; set; } = "application/json";


            public int Timeout { get; set; } = -1;


            public bool useformdata { get; set; }

            public Dictionary<string, string> headers { get; set; } = new Dictionary<string, string>();

        }

        private ApiResult RestSharpCall(RestSharpVerb ent)
        {
            var apiresult = new ApiResult() { Success = false };
            var aoption = new RestClientOptions() { MaxTimeout = -1 };
            try
            {
                var client = new RestClient(options: aoption);
                var request = new RestRequest(ent.url, ent.method);
                request.AddHeader("Content-Type", "application/json");
                if (ent.headers != null && ent.headers.Count > 0)
                {
                    foreach (var header in ent.headers)
                    {
                        request.AddHeader(header.Key, header.Value);
                    }
                }
                request.AddHeader("Content-Type", "application/json");
                request.AddStringBody(ent.body, DataFormat.Json);
                RestResponse response = client.Execute(request);
                var rescontent = response.Content;
                if (!string.IsNullOrWhiteSpace(rescontent))
                {
                    apiresult.Content = rescontent;
                    apiresult.Success = true;
                }
            }
            catch (Exception ex)
            {
                apiresult.ErrorException = ex;
            }
            return apiresult;
        }
        private void Sign(RequestDto dto, string appsecret)
        {
            dto.timestamp = DateTimeToUnixTimestampSeconds(DateTime.Now);
            dto.sign = EncodeHelper.MD5_32(EncodeHelper.Encrypt(appsecret, "") + dto.data + dto.timestamp);
        }

        private long DateTimeToUnixTimestampSeconds(DateTime dateTime)
        {
            DateTime dateTime2 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            return (long)(dateTime.ToUniversalTime() - dateTime2).TotalSeconds;
        }

        public ApiResult CallApi(Method method, string url, string dataparams, RequestOption option)
        {
            RestSharpVerb restSharpVerb = new RestSharpVerb();
            restSharpVerb.method = method;
            restSharpVerb.ConvertApiResultData = option.ConvertApiResultData;
            restSharpVerb.url = url;
            restSharpVerb.contenttype = "application/json";
            bool withsign = option.withsign;
            string appsecret = option.appsecret;
            if (!string.IsNullOrWhiteSpace(option.contenttype))
            {
                restSharpVerb.contenttype = option.contenttype;
            }
            if (option.headers.Count > 0)
            {
                restSharpVerb.headers = option.headers;
            }
            if (option.Timeout > -1)
            {
                restSharpVerb.Timeout = option.Timeout;
            }
            if (option.useformdata)
            {
                restSharpVerb.parameters = JsonConvert.DeserializeObject<Dictionary<string, string>>(dataparams);
            }
            else
            {
                string body = "";
                if (dataparams != null)
                {
                    if (withsign)
                    {
                        RequestDto requestdto = new RequestDto();
                        requestdto.data = EncodeHelper.Encrypt(dataparams, "");
                        Sign(requestdto, appsecret);
                        body = JsonConvert.SerializeObject(requestdto);
                    }
                    else
                    {
                        body = dataparams;
                    }
                }
                restSharpVerb.body = body;
            }
            return RestSharpCall(restSharpVerb);
        }
    }
}
